#include<iostream>
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<vector>
#include<string>
#include<cerrno>
#include<cstdlib>


enum
{
  OK,
  USAGE_ERR,
  CREATPCB_ERR,
  WAIT_ERR
};

typedef void (*callback_t)();


void Test()
{
  int cnt=5;
  while(cnt--)
  {
    printf("我是一个子进程，我在完成Test任务，pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt);
    sleep(1);
  }
}

void Task()
{
  int cnt=5;
  while(cnt--)
  {
    printf("我是一个子进程，我在完成Task任务，pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt);
    sleep(1);
  }
}

void Hello()
{
  int cnt=5;
  while(cnt--)
  {
    printf("我是一个子进程，我在完成Hello任务，pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt);
    sleep(1);
  }
}

///////////////////////////////////////////////////////////////////////////////////

//int CreatChildProcess(int num,std::vector<pid_t>* subs,callback_t cb)
int CreatChildProcess(int num,std::vector<pid_t>* subs,std::vector<callback_t>& cb)
{
  for(int i=0;i<num;i++)
  {
    pid_t id=fork();
    if(id==-1)
    {
      std::cout<<"创建子进程"<<i<<"失败"<<std::endl;
      exit(CREATPCB_ERR);
    }
    else if(id==0)
    {
      for(const auto& fc:cb)
      {
        fc();
      }
      exit(OK);
    }
    subs->push_back(id);
  }
  return OK;
}

int WaitAllChild(std::vector<pid_t>& subs)
{
  for(const auto& pid:subs)
  {
    int status=0;
    pid_t rid=waitpid(pid,&status,0);
    if(rid==-1)
    {
      printf("pid:%d 子进程等待失败\n",pid);
      exit(WAIT_ERR);
    }
    else
    {
      printf("子进程：%d Exit,exit code: %d\n",rid,WEXITSTATUS(status));
    }
  }
  return OK;
}

int main(int argc,char* argv[])
{
  if(argc!=2)
  {
    std::cout<<"Usage: "<<argv[0]<<" process_num"<<std::endl;
    exit(USAGE_ERR);
  }
  int num=std::stoi(argv[1]);
  std::vector<pid_t> subs;

  //创建多进程
  //int exit_code = CreatChildProcess(num,&subs,Hello);
  //if(exit_code==CREATPCB_ERR)
  //  exit(errno);

  std::vector<callback_t> fc;
  fc.push_back(Hello);
  fc.push_back(Task);
  fc.push_back(Test);

  int exit_code = CreatChildProcess(num,&subs,fc);
  if(exit_code==CREATPCB_ERR)
    exit(errno);
 
  sleep(8);

  //父进程
  exit_code = WaitAllChild(subs);
  if(exit_code==WAIT_ERR)
    exit(errno);

  return OK;
}
